package com.gemini.main.counter;

import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * com.gemini.main.counter.CompensationCounter
 *
 * @author zhanghailin
 */
public class CompensationCounter implements Counter {

    private ConcurrentHashMap<String, Adder> map = new ConcurrentHashMap<>();

    @Override
    public void save(Saver saver) {
        for (Iterator<Map.Entry<String, Adder>> it = map.entrySet().iterator(); it.hasNext(); ) {
            Map.Entry<String, Adder> entry = it.next();
            it.remove();
            entry.getValue().discarded = true;
            saver.save(entry.getKey(), entry.getValue().like.getAndSet(0), entry.getValue().comment.getAndSet(0));//需将计数器置0，此处存在竞争
        }
    }

    @Override
    public void add(String key, int like, int comment) {
        Adder adder = map.computeIfAbsent(key, k -> new Adder());
        adder.like.addAndGet(like);
        adder.comment.addAndGet(comment);
        if (adder.discarded) {//如果数量加在了废弃的Adder上面，则执行补偿逻辑
            int likeTemp = adder.like.getAndSet(0);
            int commentTemp = adder.comment.getAndSet(0);
            //即使此后又有线程在计数器上计数了也无妨
            if (likeTemp != 0 || commentTemp != 0) {
                add(key, likeTemp, commentTemp);//补偿
            }//也可能已经被其它线程取走了，但并不影响业务正确性
        }
    }

    static class Adder {
        AtomicInteger like = new AtomicInteger();
        AtomicInteger comment = new AtomicInteger();
        volatile boolean discarded = false;//只有保存线程会将它改为true，故使用volatile便能保证线程安全
    }
}
